<template>
  <div v-loading="loading">
    <el-table
      ref="table"
      v-bind="{ ...props }"
      :data="data"
      style="width: 100%"
      :row-class-name="tabRowClassName"
      @select="handleSelectionChange"
      :row-style="rowStyle"
      @select-all="handleSelectionChange"
      :cell-class-name="cellClassName"
      header-row-class-name="custom-table-header"
      :default-expand-all="expendAll"
      row-key="id"
      :max-height="maxHeight"
    >
      <!-- 单选框 -->
      <el-table-column
        v-if="showCheckBoX"
        width="55"
        type="selection"
        :reserve-selection="keep"
        :class-name="turnRadio ? `checkBoxRadio` : ``"
        align="center"
      ></el-table-column>
      <!-- 单选框 -->
      <el-table-column v-if="showRadioCheck" width="55" type="index">
        <template #default="{ row }">
          <el-radio v-if="row.from === 'o'" @change="rowClick(row)" :label="row.id" v-model="radioId">&nbsp;</el-radio>
        </template>
      </el-table-column>
      <!-- 序号 -->
      <el-table-column v-if="showTypeIndex" align="center" label="序号" width="50">
        <template #default="{ $index }">{{ $index + 1 }}</template>
      </el-table-column>
      <!-- 表格 -->
      <el-table-column
        v-for="item in tableLabel.filter((item) => item.label)"
        :width="item.width ? item.width : ''"
        :key="item[keyId]"
        :align="!!item.align ? item.align : 'center'"
        :label="item.label"
        :show-overflow-tooltip="overflowText"
        :fixed="item.fixed"
        :prop="item.prop"
      >
        <template #default="{ row }">
          <template v-if="item.Image">
            <div>
              <el-image class="table-img" :src="row.attachment" :preview-src-list="[row.attachment]">
                <template #error>
                  <span>无</span>
                </template>
              </el-image>
            </div>
          </template>
          <!--开关-->
          <template v-else-if="item.switch">
            <el-switch :active-value="item.active"  :inactive-value="item.inactive" v-model="row[item.prop]" active-color="#13ce66" @change="changeSwitch(row)"></el-switch>
          </template>
          <!--输入-->
          <template v-else-if="item.input">
            <el-input v-model="row[item.prop]" :maxlength='item.length' :show-word-limit='item.length' :type="item.inputType || 'text'" v-bind="item.attr" @change="changeinput(row)"></el-input>
          </template>
          <!--进度条-->
          <template v-else-if="item.progress">
            <el-progress class="progress-line" :text-inside="true" :stroke-width="26" :percentage="row[item.prop]"></el-progress>
          </template>
          <!-- 自定义渲染 -->
          <template v-else-if="item.render">
            <div style="cursor: pointer" @click="!!item.methods && handleClickon(item.methods, row)" v-html="item.render(row)"></div>
          </template>
          <!-- 自定义标签 -->
          <template v-else-if="item.customTag">
            <el-tag :class="'el-tag--' + getCustomTagName(item.customTagName, row)">{{ row[item.prop] }}</el-tag>
          </template>
          <!-- 默认展示值 -->
          <template v-else>
            <div class="text-no-wrap" @click="!!item.methods && handleClickon(item.methods, row)">
              {{ row[item.prop] }}
            </div>
          </template>
        </template>
      </el-table-column>
      <el-table-column v-if="!!option" :width="option.width" :label="option.label" :fixed="option.fixed" align="center">
        <template #default="scope" v-if="!!option.children">
          <!-- 常规正常情况 -->
          <template>
            <!-- 按钮列表 组合使用 -->
            <div v-if="option.children.length > 2">
              <el-button
                type="text"
                v-for="(item, index) in option.children.slice(0, 1)"
                :key="index"
                v-show="!buttonHidden(item, scope.row)"
                v-bind="{ ...item.props }"
                :disabled="buttonDisabled(item, scope.row)"
                @click="handleTableButton(item.methods, scope.row, index, scope.$index)"
                :class="['btn-' + item.methods, 'btn-right']"
                size="mini"
              >
                <template v-if="item.render">
                  <div v-html="item.render(scope.row)"></div>
                </template>
                {{ !!item.label ? item.label : '' }}
              </el-button>
              <el-dropdown trigger="click">
                <span class="el-dropdown-link">
                  <el-button type="text">更多</el-button>
                </span>
                <template #dropdown>
                  <el-dropdown-menu>
                    <el-dropdown-item v-for="(item, index) in option.children.slice(1)" :key="index">
                      <el-button
                        type="text"
                        v-show="!buttonHidden(item, scope.row)"
                        v-bind="{ ...item.props }"
                        :disabled="buttonDisabled(item, scope.row)"
                        @click="handleTableButton(item.methods, scope.row, index, scope.$index)"
                        :class="['btn-' + item.methods, 'btn-right']"
                        size="mini"
                      >
                        <template v-if="item.render">
                          <div v-html="item.render(scope.row)"></div>
                        </template>
                        {{ !!item.label ? item.label : '' }}
                      </el-button>
                    </el-dropdown-item>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </div>
            <!-- 按钮列表 全部水平 -->
            <div v-else>
              <el-button
                type="text"
                v-for="(item, index) in option.children"
                :key="index"
                v-show="!buttonHidden(item, scope.row)"
                v-bind="{ ...item.props }"
                :disabled="buttonDisabled(item, scope.row)"
                @click="handleTableButton(item.methods, scope.row, index, scope.$index)"
                :class="['btn-' + item.methods, 'btn-right']"
                size="mini"
              >
                <template v-if="item.render">
                  <div v-html="item.render(scope.row)"></div>
                </template>
                {{ !!item.label ? item.label : '' }}
              </el-button>
            </div>
          </template>
        </template>
      </el-table-column>
    </el-table>
    <Pagination
      v-show="pageInfo.totalCount > 0"
      :total="pageInfo.totalCount"
      :page="pageInfo.pageIndex"
      :limit="pageInfo.pageSize"
      :pageSizes="pageInfo.pageArr"
      @pagination="getList"
    />
  </div>
</template>

<script lang="ts">
  import {
    defineComponent,
    PropType,
    ref,
    nextTick,
    watch,
    toRaw
  } from 'vue'
  import { Utils } from '@/utils'
  import { isNumber } from '@/utils/is'
  import {
    TableLabel,
    TableOption
  } from '../types'

  export default defineComponent({
    name: 'CommonTable',
    props: {
      maxHeight: {
        type: [String, Number],
        default: 600
      },
      stateArr: {
        type: Array,
        default: () => {
          return []
        }
      },
      tableLabel: {
        // 表格展示
        type: Array as PropType<Array<TableLabel>>,
        default: () => {
          return []
        }
      },
      data: {
        // 数据源
        type: Array as PropType<Array<any>>,
        default: () => {
          return []
        }
      },
      option: {
        // 配置需要显示的操作菜单
        type: Object as PropType<TableOption>
      },
      showCheckBoX: {
        // 配置是否显示全选（复选框）
        type: Boolean,
        default: false
      },
      showRadioCheck: {
        // 配置是否显示单选框
        type: Boolean,
        default: false
      },
      showTypeIndex: {
        type: Boolean,
        default: false
      },
      turnRadio: {
        type: Boolean,
        default: false
      },
      selectedIdArr: {
        type: Array,
        default: []
      },
      pageInfo: {
        // 配置分页
        type: Object,
        default: () => {
          return {
            pageIndex: 1,
            totalCount: 0,
            pageSize: 10,
            pageArr: []
          }
        }
      },
      showPagination: {
        // 是否隐藏 分页显示
        type: Boolean,
        default: true
      },
      overflowText: {
        // 是否 隐藏文字过长
        type: Boolean,
        default: false
      },
      loading: {
        // loading 配置
        type: Boolean,
        default: false
      },
      keep: {
        type: Boolean,
        default: false
      },
      keyId: {
        // 动态绑定 key 值
        type: String,
        default: 'id'
      },
      props: {
        // 表格参数配置
        type: Object,
        default: function () {
          return {
            'show-header': true, // 显示表头e
            'highlight-current-row': false, // 是否要高亮当前行
            'tooltip-effect': 'dark', //
            'max-height': 'auto', // Table 的最大高度。合法的值为数字或者单位为 px 的高度。
            'empty-text': '没有数据', // 空数据显示状态
            'element-loading-text': '加载中', // loading 加载
            'header-cell-style': {
              background: '#F2F4F7',
              color: '#333',
              fontSize: '13px'
            }, // 表头样式
            border: false, // 是否带有纵向边框
            fit: true, // 列的宽度是否自撑开
            stripe: false // 是否显示斑马纹
          }
        }
      },
      rowStyle: {
        type: Object,
        default: () => {
          return {
            height: '40px'
          }
        }
      },
      expendAll: {
        type: Boolean,
        default: false
      }
    },
    setup(props, { emit }) {
      watch(
        () => props.data,
        () => {
          if (props.showCheckBoX || props.turnRadio) {
            nextTick(() => {
              table.value.clearSelection()
              curPageCheck.value = []
              if (props.showCheckBoX && props.turnRadio) {
                props.data.filter((item: any) => {
                  if (item.id == props.selectedIdArr[0]) {
                    table.value.toggleRowSelection(item, true)
                  }
                })
              } else if (props.showCheckBoX) {
                props.data.filter((item: any) => {
                  if (props.selectedIdArr.includes(item.id)) {
                    table.value.toggleRowSelection(item, true)
                    curPageCheck.value.push(item.id)
                  }
                })
              }
            })
          }
        },
        {
          deep: true,
          immediate: true
        }
      )

      watch(
        () => props.selectedIdArr,
        (val) => {
          if (props.showCheckBoX || props.turnRadio) {
            nextTick(() => {
              table.value.clearSelection()
              curPageCheck.value = []
              if (props.showCheckBoX && props.turnRadio) {
                props.data.filter((item: any) => {
                  if (item.id == val[0]) {
                    table.value.toggleRowSelection(item, true)
                  }
                })
              } else if (props.showCheckBoX) {
                props.data.filter((item: any) => {
                  if (val.includes(item.id)) {
                    table.value.toggleRowSelection(item, true)
                    curPageCheck.value.push(item.id)
                  }
                })
              }
            })
          }
        },
        {
          deep: true
        }
      )
      const getCustomTagName = (e: any, row: any): string => {
        let customTagName = ''
        if (Object.prototype.toString.call(e) === '[object Function]') {
          customTagName = e(row)
        } else {
          customTagName = e
        }
        return customTagName
      }
      /**
       * prop 单值 或者 数组过滤(此处为针对时间组，不作为通用处理)
       */
      const propFilter = (prop: [Array<any> | object], row: any) => {
        let res = prop.reduce((total: string, cur: any) => {
          if (row[cur]) {
            return (total += row[cur] + '~')
          } else {
            return ''
          }
        }, '')
        // console.log(res)
        return res ? res.replace(/~$/, '') : ''
      }
      const handleTableButton = (methods: any, row: object, index: number, rowIndex: number) => {
        // 按钮事件
        emit('handleTableButton', { methods, row, index, rowIndex })
      }
      const handleClickon = (methods: any, row: object) => {
        if (typeof methods !== 'string') throw '方法名错误'
        // 数据操作
        emit(methods, { methods, row })
      }
      const curPageCheck = ref<Array<any>>([])
      const handleSelectionChange = (val: Array<any>) => {
        let arr = val.map((item) => parseInt(item.id))
        let compare = Utils.compareArray(curPageCheck.value, arr)
        if (props.showCheckBoX && props.turnRadio) {
          // 选择项大于1时
          if (val.length > 1) {
            let del_row = val.shift()
            table.value.toggleRowSelection(del_row, false)
          }
        }
        // 全选
        if (props.showCheckBoX && props.selectedIdArr) {
          if (props.turnRadio) {
            emit('handleSelectionChange', val)
          } else {
            emit('handleSelectionChange', val, compare)
          }
        } else {
          emit('handleSelectionChange', val)
        }
      }
      const getList = (pages: any) => {
        let { page, limit } = pages
        if (!isNumber(page)) {
          page = page.value
        }
        if (!isNumber(limit)) {
          limit = limit.value
        }
        const pageInfo = {
          page,
          limit
        }
        emit('handleGetList', pageInfo)
      }
      const getRowKeys = (row: any) => {
        return row.id
      }
      const table = ref<any>(null)

      const selectAll = (val: any) => {
        if (props.showCheckBoX && props.turnRadio) {
          // 选择项大于1时
          if (val.length > 1) {
            val.length = 1
          }
        }
        emit('handleSelectionChange', val)
      }

      //斑马纹表格背景色
      const tabRowClassName = ({ row, rowIndex }: any) => {
        let index = rowIndex + 1
        if (index % 2 == 0) {
          return 'even-row'
        } else {
          return 'odd-row'
        }
      }

      const cellClassName = ({ row, column, rowIndex, columnIndex }: any) => {
        if (row.confirmTag === 2 && columnIndex < (props as any).tableLabel.length) {
          return 'height_light_cell'
        } else {
          return ''
        }
      }

      const buttonHidden = (item: any, row?: any) => {
        if (typeof item.hidden === 'function') return item.hidden(row) || false
        if (!item.hidden) return item.hidden
      }

      const buttonDisabled = (item: any, row?: any) => {
        if (typeof item.disabled === 'function') return item.disabled(row) || false
        if (!item.disabled) return item.disabled
      }
      const showVertical = ref<boolean>(false)
      /**
       * 单选框选中事件
       */
      const rowClick = (row: any): void => {
        emit('rowClick', row)
      }
      const radioId = ref<number | string>(-1)
      //switch-change事件
      const changeSwitch = (row: any): void => {
        emit('rowChange','switch', toRaw(row))
      }
      //input-change事件
      const changeinput = (row: any): void => {
        emit('rowChange', 'input',toRaw(row))
      }

      return {
        propFilter,
        handleTableButton,
        handleClickon,
        handleSelectionChange,
        getList,
        getRowKeys,
        tabRowClassName,
        cellClassName,
        buttonHidden,
        buttonDisabled,
        showVertical,
        table,
        radioId,
        rowClick,
        getCustomTagName,
        selectAll,
        changeSwitch,
        changeinput
      }
    }
  })
</script>

<style lang="scss" scoped>
  @import '@/styles/index.scss';

  ::v-deep .el-table__header,
  ::v-deep .el-table__body {
    margin: 0;
  }

  .scrollBar {
    @include scrollBar;
  }

  ::v-deep .el-table::before {
    height: 0;
  }

  ::v-deep .el-button {
    padding: 0;
    border: none;
    margin: 0 4px;
    padding: 0 4px 0 8px;
    border-left: 1px solid #e2e2e2;
    font-size: 14px;
    min-height: 14px;

    &:first-child {
      border-left: none;
    }
  }

  ::v-deep .el-button + .el-button {
    margin-left: 0;
  }

  .btn-see {
    color: #39a6ff;
  }

  .btn-handel {
    color: #41a4bd;
  }

  .btn-edit {
    color: #fcb0fb;
  }

  .btn-delete,
  .btn-del {
    color: #fd9090;
  }

  .btn-revoke {
    color: #ffa913;
  }

  ::v-deep .btn-right div {
    margin-right: 5px;
  }

  .btn-right div:empty {
    margin-right: 0px;
  }

  //斑马纹表格背景色
  ::v-deep(.el-table) .even-row {
    --el-table-tr-background-color: #f5fafb;
  }

  ::v-deep(.el-table) .odd-row {
    --el-table-tr-background-color: #ffffff;
  }

  .el-table--border::after,
  .el-table--group::after {
    width: 0;
  }

  ::v-deep .el-table td,
  th.is-leaf {
    border: none;
  }

  ::v-deep .el-table__fixed-right::before,
  .el-table__fixed::before {
    background-color: transparent;
  }

  ::v-deep .custom-table-header {
    th {
      background-color: #62c4ee !important;
      color: #fff !important;
    }
  }

  .progress-line {
    .el-progress-bar__outer {
      height: 16px !important;
    }

    .el-progress-bar__outer,
    .el-progress-bar__inner {
      border-radius: 0 !important;
    }
  }

  .text-no-wrap {
    @include text-no-wrap;
    cursor: pointer;
    display: inline;
  }

  ::v-deep(.el-table) {
    td.el-table__cell div,
    th.el-table__cell > .cell {
      font-size: 14px;
    }

    th.el-table__cell > .cell {
      font-weight: normal;
    }

    .cell {
      padding: 0 10px;
      line-height: 39px;
    }

    .el-table__header-wrapper .checkBoxRadio .el-checkbox {
      display: none;
    }

    .el-checkbox {
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .table-img {
      width: 60px;
      height: 60px;
      object-fit: cover;
      padding: 6px 0;
      display: flex;
      align-items: center;
      margin: 0 auto;
      justify-content: center;
    }
  }

  ::v-deep(.el-table--small .el-table__cell) {
    padding: 0;
  }

  ::v-deep(.el-dropdown-menu__item) {
    padding: 0 !important;
    .el-button {
      width: 100%;
      text-align: center;
      padding: 0 8px;
      margin: 0;
    }
  }
</style>
